
include("cl_circle.lua")
include("shared.lua")
include("cl_menu.lua")

SWEP.PrintName = "LuaChip Gun"
SWEP.Slot = 5
SWEP.SlotPos = 7
SWEP.DrawAmmo = false
SWEP.DrawCrosshair = true

//There are only so many ways to do 1+1
local matScreen = Material("models/weapons/v_toolgun/screen")
local rtScreen = GetRenderTarget("LuaChipScreen",512,512)

function SWEP:ViewModelDrawn()
	self.numrenders = self.numrenders + 1
	//Prevent recursion
	if rtScreen then
		if self.numrenders <= 1 then
			local m = self:GetMouseTable()
			
			matScreen:SetMaterialTexture("$basetexture",rtScreen)
			rtOld = render.GetRenderTarget()
			
			render.SetRenderTarget(rtScreen)
			render.SetViewPort(0,0,512,512)
			
			local drawscreen = self.DrawScreen or function() end
			
			cam.Start2D()
				local b,e = pcall(drawscreen,self,m,0,0,512,512)
				if not b then
					ErrorNoHalt("\n" .. tostring(e))
				end
			cam.End2D()
			
			render.SetRenderTarget(rtOld)
			render.SetViewPort(0,0,ScrW(),ScrH())
			
			--"
			//Think
			
			if self.Owner == LocalPlayer() then
				if LocalPlayer():KeyDown(IN_RELOAD) and not LocalPlayer():KeyDownLast(IN_RELOAD) then
					self.editMode = true
					self:MouseActive(true)
				end
			end
		else
			return false
		end
	else
		Error("Ensure settings/render_targets/LuaChipScreen.txt exists, then restart GMOD. You can download this file at http://luachip.googlecode.com/svn/trunk/settings/render_targets/LuaChipScreen.txt\n")
	end
end

SWEP.editMode = false
SWEP.EditSpleen = 0

function SWEP:IsEquipped()
	local stack = LocalPlayer()
	if not IsValid(stack) then
		return false
	end
	stack = stack:GetActiveWeapon()
	if not IsValid(stack) then
		return false
	end
	if not (stack:GetClass() == "weapon_luachip") then
		return false
	end
	return true
end

SWEP.numrenders = 0
function SWEP:ThinkSub()
	//TODO: Move these to initialize
	
	local self = self
	
	hook.Add("RenderScene","luachipgun",function()
		self.numrenders = 0
	end)
	
	hook.Add("HUDPaint","luachipgun",function()
		if not IsValid(self) or not self:IsEquipped() then
			//self:MouseActive(false)
			return
		end
		
		//We are equipped!
		if self.Active then
			local kbs = luachip.kbs
			
			if kbs then
				if kbs.frame and kbs.frame:IsVisible() then
					kbs.frame:SetSize(ScrW(),ScrH())
					kbs.frame:SetPos(0,0)
					local x,y = kbs.frame:GetPos()
					local w,h = kbs.frame:GetSize()
					
					local col = Color(255,255,255,255)
					if not self.Onscreen then
						col = Color(255,0,0,255)
					end
					draw.DrawText("X","Trebuchet24",x+w-8,y,col,2)
				elseif self.Active then
					self:MouseActive(false)
				end
			end
		end
	end)
	
	hook.Add("PlayerBindPress","luachipgun",function(pl,bind,pressed)
		if pl ~= LocalPlayer() then
			return
		end
		
		if not IsValid(self) or not self:IsEquipped() then
			//self:MouseActive(false)
			return
		end
		
		
		if bind:find("+menu_context") then
			if pressed then
				self:MouseActive(true)
				return true
			else
				//This won't get called until garry changes something
			end
		end
	end)
end

SWEP.Onscreen = false
SWEP.Active = false
SWEP.MouseClick = {
	wheel = 0,
}
SWEP.MouseDat = {}
function SWEP:MouseActive(state)
	if not luachip then
		return
	end
	
	//We are doin' some crazy shit with the scope here
	local SWEP = self
	
	if state then
		if not self.Active then
			//Activate
			self.MouseClick = {}
			for i = 0,4 do
				self.MouseClick[i] = 0
			end
			self.MouseClick.wheel = 0
			self.MouseDat = {}
			
			local kbs = {}
			kbs.frame = vgui.Create("Frame")
			kbs.frame:SetName("luachipkeyboardspy")
			kbs.frame:SetTextInset("Emergency Stop")
			function kbs.frame:Init()
				
			end
			function kbs.frame:OnKeyCodePressed(char)
				if char == 57 then
					Msg("Manually closing LuaChip keyboard spy (Tilde pressed.)\n")
					SWEP:MouseActive(false)
					return
				end
				
				SWEP.char = SWEP.char or {}
				table.insert(SWEP.char,char)
			end
			function kbs.frame:OnMousePressed(mc)
				mc = mc - 107
				SWEP.MouseClick[mc] = 1
			end
			function kbs.frame:OnMouseReleased(mc)
				mc = mc - 107
				SWEP.MouseClick[mc] = -1
			end
			function kbs.frame:OnMouseWheeled(delta)
				SWEP.MouseClick.wheel = delta
			end
			kbs.frame:SetVisible(true)
			kbs.frame:SetSize(ScrW(),ScrH())
			kbs.frame:SetPos(0,0)
			kbs.frame:SetPaintedManually(true)
			
			luachip.kbs = kbs
			
			gui.EnableScreenClicker(true)
			self.Active = true
		end
	elseif self.Active then
		//Deactivate
		self.MouseClick = {
			wheel = 0,
		}
		self.MouseDat = {}
		
		local kbs = luachip.kbs
		
		if kbs then
			if kbs.frame and kbs.frame:IsVisible() then
				kbs.frame:Remove()
			end
		end
		
		gui.EnableScreenClicker(false)
		self.Active = false
		self.editMode = false
	end
end

function SWEP:OnRemove()
	if self.Owner == LocalPlayer() then
		self:MouseActive(false)
	end
end

function SWEP:SaveMouseTable(m)
	self.MouseClick = m.c
	self.MouseDat = m.dat
end

function SWEP:GetMouseTable()
	//This code may become as "famous" as the i88's cursor finding routine
	//WARNING: CONTENT HIGHLY RELISHABLE. ADD MAYONNAISE.
	
	local m = {
		x = -1,
		y = -1,
	}
	m.c = self.MouseClick
	m.dat = self.MouseDat
	do //*Wonders how many don't know why I put a "do" and "end" here*
		local out
		local pos = self.Owner:GetShootPos()
		//local vehicle = self.Owner:GetVehicle() //Note to thieves: Just add this to dir and normalize angles, then vector-normalize
		local dir = self.Owner:GetCursorAimVector()
		
		local vp,va = self:GetViewModelPosition(self.Owner:GetShootPos(),self.Owner:EyeAngles())
		
		local sp = self.ScrPos
		vp = vp + va:Forward()*sp.x
		vp = vp + va:Right()*sp.y
		vp = vp + va:Up()*sp.z
		
		va:RotateAroundAxis(va:Right(),45)
		
		local nor = va:Up()
		local pln = vp
		
		local a = nor:DotProduct(pln-pos)
		local b = nor:DotProduct(dir)
		out = a/b
		
		//Out is now the distance from view to plane
		
		out = pos + out*dir
		m.debugvec = out
		
		//Out is now the 3D position of the cursor
		//Find X
		m.x = 0
		do
			local pln = vp
			local nor = va:Right()
			local dir = va:Right()*-1
			
			local a = nor:DotProduct(pln-out)
			local b = nor:DotProduct(dir)
			m.x = a/b
		end
		
		//Find Y
		m.y = 0
		do
			local pln = vp
			local nor = va:Forward()*-1
			local dir = va:Forward()
			
			local a = nor:DotProduct(pln-out)
			local b = nor:DotProduct(dir)
			m.y = a/b
		end
		
		//Have the decency to leave this comment here if you use this algorithm
		//This one too; --Night-Eagle
		//The Find X and Find Y code is completely original - if you steal it, ARGGHHRHGHHGHGHGHRG *unleash cthulhu*
		
		//Convert from inches to pixels
		m.x = math.Round(m.x/2.248*512)
		m.y = math.Round(m.y/2.248*512)
		
		if m.x >= 0 and m.x <= 512 and m.y >= 0 and m.y <= 512 then
			m.onscreen = true
		end
	end
	
	return m
end

SWEP.ReadyAng = Vector(0,0,0)
SWEP.ReadyPos = Vector(-4,-16,1.2)
SWEP.EditAng = Vector(45,0,0)
SWEP.EditPos = Vector(-5.7,-19,.5)
SWEP.ScrPos = Vector(21.9,4.578,-1.775)

SWEP.lastgvmp = UnPredictedCurTime()
function SWEP:GetViewModelPosition(Apos,Aang)
	local delta = UnPredictedCurTime() - self.lastgvmp
	self.lastgvmp = UnPredictedCurTime()
	
	local rx,ry,rz = Aang:Right(),Aang:Forward(),Aang:Up()
	local goal = self.editMode and 1 or 0
	local m = math.Approach(self.EditSpleen,goal,delta/.4)
	self.EditSpleen = m
	
	Aang:RotateAroundAxis(rx,self.EditAng.x*m)
	Aang:RotateAroundAxis(rz,self.EditAng.y*m)
	Aang:RotateAroundAxis(ry,self.EditAng.z*m)
	
	m = 1-m
	Aang:RotateAroundAxis(rx,self.ReadyAng.x*m)
	Aang:RotateAroundAxis(rz,self.ReadyAng.y*m)
	Aang:RotateAroundAxis(ry,self.ReadyAng.z*m)
	m = 1-m
	
	local rx,ry,rz = Aang:Right(),Aang:Forward(),Aang:Up()
	Apos = Apos + rx*self.EditPos.x*m
	Apos = Apos + ry*self.EditPos.y*m
	Apos = Apos + rz*self.EditPos.z*m
	
	m = 1-m
	Apos = Apos + rx*self.ReadyPos.x*m
	Apos = Apos + ry*self.ReadyPos.y*m
	Apos = Apos + rz*self.ReadyPos.z*m
	m = 1-m
	
	self.BobScale = 1-m
	self.SwayScale = 1-m
	self.ViewModelFOV = 75
	
	self.DrawCrosshair = not self.editMode
	
	return Apos,Aang
end

usermessage.Hook("lcc",function(um)
	luachipswepconsolebuffer = um:ReadString()
end)

usermessage.Hook("lclink",function(um)
	luachipsweplink = {}
	local dat = luachipsweplink
	dat.ent = um:ReadEntity()
	dat.qty = um:ReadShort()
	dat.links = {}
	for i=1,dat.qty do
		dat.links[i] = {
			id = um:ReadString(),
			ent = um:ReadEntity(),
			description = um:ReadString(),
		}
	end
	Msg("RECV XMIT LINK\n")
	PrintTable(dat)
end)

usermessage.Hook("lcswepalt",function(um)
	local ent = um:ReadEntity()
	local valid = false
	for k,v in pairs(LocalPlayer():GetWeapons()) do
		if v:GetClass() == "weapon_luachip" then
			valid = v
		end
	end
	if valid then
		local dat = valid.luachipactiondata
		
		if LocalPlayer():GetActiveWeapon() == valid and valid.activetab == 1 and valid.activeaction == 4 then
			if luachipsweplink and luachipsweplink.links then
				local i = dat.Link.cur
				local id = luachipsweplink.links[i].id
				
				if IsEntity(luachipsweplink.ent) and IsEntity(ent) then
					RunConsoleCommand("lclink",id,luachipsweplink.ent:EntIndex(),ent:EntIndex())
				end
			end
		end
	end
end)

//Scroll hook
//(I wrote the damned wire_adv tool, so no bitching about how I stole code from myself)

local last = CurTime()
hook.Add("PlayerBindPress","luachipswep_scrollhook",function(pl,bind,pressed)
	if last == CurTime() then
		return
	end
	last = CurTime()
	local ldat = luachipsweplink
	if ldat and ldat.ent and ldat.links and #ldat.links > 1 then
		local valid = false
		for k,v in pairs(pl:GetWeapons()) do
			if v:GetClass() == "weapon_luachip" then
				valid = v
			end
		end
		if valid then
			if pl:GetActiveWeapon() == valid and valid.activetab == 1 and valid.activeaction == 4 then
				local dat = valid.luachipactiondata
				if dat.Link.cur then
					if string.find(bind,"invnext") then
						local count = #ldat.links
						dat.Link.cur = dat.Link.cur + 1
						if dat.Link.cur > #ldat.links then
							dat.Link.cur = #ldat.links
						end
						return true
					elseif string.find(bind,"invprev") then
						dat.Link.cur = dat.Link.cur - 1
						if dat.Link.cur < 1 then
							dat.Link.cur = 1
						end
						return true
					end
				end
			end
		end
	end
end)





















































